package de.ret_world.eet.encryption;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A Helper class to save data to files
 * @author Emu
 */
public class IO {

    /**
     * Loads a File into a binary string
     * @param file the file to load
     * @return a binary string
     */
    public static String loadFileToBinaryString(File file) {
        FileInputStream in = null;
        byte[] bytes = null;
        try {
            in = new FileInputStream(file);
            bytes = new byte[(int) file.length()];
            int offset = 0;
            int numRead = 0;
            while (offset < bytes.length
                    && (numRead = in.read(bytes, offset, bytes.length - offset)) >= 0) {
                offset += numRead;
            }
            if (offset < bytes.length) {
                throw new IOException("Could not completely read file " + file.getName());
            }
        } catch (IOException ex) {
            Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        StringBuilder bin = new StringBuilder();

        for (byte b : bytes) {
            String tmp = Integer.toBinaryString(b);
            int diff = 8 - tmp.length();
            if (diff > 0) {
                for (int x = 0; x < diff; x++) {
                    if (b > 0) {
                        tmp = "0" + tmp;
                    } else {
                        tmp = "1" + tmp;
                    }
                }
            } else {
                tmp = tmp.substring(tmp.length() - 8, tmp.length());
            }
            bin.append(tmp);
        }
        return bin.toString();
    }

    /**
     * Loads a File into a String
     * @param file the file
     * @return the string
     */
    public static String loadFileToString(File file) {
        BufferedReader in = null;
        StringBuilder out = new StringBuilder();
        try {
            in = new BufferedReader(new FileReader(file));
            String s;
            while ((s = in.readLine()) != null) {
                out.append(s);
                out.append("\n");
            }
        } catch (IOException ex) {
            Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return out.toString();
    }

    /**
     * Loads a File to a Hex String
     * @param file the file
     * @return the hex string
     */
    public static String loadFileToHexString(File file) {
        FileInputStream in = null;
        byte[] bytes = null;
        try {
            in = new FileInputStream(file);
            bytes = new byte[(int) file.length()];
            int offset = 0;
            int numRead = 0;
            while (offset < bytes.length
                    && (numRead = in.read(bytes, offset, bytes.length - offset)) >= 0) {
                offset += numRead;
            }
            if (offset < bytes.length) {
                throw new IOException("Could not completely read file " + file.getName());
            }
        } catch (IOException ex) {
            Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        StringBuilder bin = new StringBuilder();

        for (byte b : bytes) {
            String tmp = Integer.toHexString(b).toUpperCase();
            if (tmp.length() < 2) {
                tmp = "0" + tmp;
            } else if (tmp.length() > 2) {
                tmp = tmp.substring(tmp.length() - 2, tmp.length());
            }

            bin.append(tmp);
        }
        return bin.toString();
    }

    /**
     * Saves a String to a file
     * @param file the file
     * @param text the string
     */
    public static void saveStringToFile(File file, String text) {
        FileWriter out = null;
        try {
            out = new FileWriter(file);
            out.write(text.replaceAll("\\n", System.getProperty("line.separator")));
        } catch (IOException ex) {
            Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Saves hex data from a string to a file
     * @param file the file 
     * @param text the hex string
     */
    public static void saveHexStringToFile(File file, String text) {
        ArrayList<Byte> bytes = new ArrayList<Byte>();
        if (text.length() % 2 != 0) {
            throw new IllegalArgumentException("No hex string!");
        }
        for (int i = 0; i < text.length(); i += 2) {
            String b = "#" + text.substring(i, i + 2);
            bytes.add(Integer.decode(b).byteValue());
        }

        byte[] byt = new byte[bytes.size()];
        for (int i = 0; i < bytes.size(); i++) {
            byt[i] = bytes.get(i);
        }

        FileOutputStream out = null;
        try {
            out = new FileOutputStream(file);
            out.write(byt);
        } catch (IOException ex) {
            Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Saves binary data from a string to a file
     * @param file the file
     * @param text the binary string
     */
    public static void saveBinaryStringToFile(File file, String text) {
        ArrayList<Byte> bytes = new ArrayList<Byte>();
        if (text.length() % 8 != 0) {
            throw new IllegalArgumentException("No binary string!");
        }
        for (int i = 0; i < text.length(); i += 8) {
            String b = text.substring(i, i + 8);
            bytes.add(Integer.valueOf(b, 2).byteValue());
        }

        byte[] byt = new byte[bytes.size()];
        for (int i = 0; i < bytes.size(); i++) {
            byt[i] = bytes.get(i);
        }

        FileOutputStream out = null;
        try {
            out = new FileOutputStream(file);
            out.write(byt);
        } catch (IOException ex) {
            Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}
